using System.Reflection;
using ASPApiDemo.Common;
using Castle.DynamicProxy;
using Newtonsoft.Json;

namespace ASPApiDemo.Extension;
//同步方法：调用 → 立即执行 → 返回结果 → 结束，拦截器可以简单地在方法前后插入代码
//异步方法：调用 → 立即返回Task对象 → 后台继续执行 → 最终完成，拦截器不能简单地"等待"方法完成，因为方法调用已经返回了
//异步方法不会阻塞调用线程，而是立即返回一个Task对象，实际工作可能在另一个线程上执行，不知道方法何时会完成
//同步方法可以直接获取返回值，异步方法返回的是Task，实际值在Task内部
//同步方法异常会立即抛出，异步方法异常会被封装在Task中
//拦截器需要在方法真正完成时记录日志，而不是在方法开始调用时
//对异步方法提供特殊处理，确保日志在方法完成后记录
public class ServiceAOP : IInterceptor
{
    // 实现IInterceptor接口的Intercept方法，用于处理方法拦截
    // invocation 参数包含了被拦截方法的所有信息（方法名、参数等）
    public void Intercept(IInvocation invocation)
    {
        string json;
        try
        {
            // 将方法参数序列化为JSON格式，用于日志记录
            json = JsonConvert.SerializeObject(invocation.Arguments);
        }
        catch (Exception ex)
        {
            // 处理无法序列化的情况（如Lambda表达式）
            json = "无法序列化，可能是兰姆达表达式等原因造成，按照框架优化代码" + ex.ToString();
        }

        // 记录方法调用的开始时间
        DateTime startTime = DateTime.Now;
        // 创建AOPLogInfo日志信息对象，记录请求的详细信息
        AOPLogInfo apiLogAopInfo = new AOPLogInfo
        {
            RequestTime = startTime.ToString("yyyy-MM-dd hh:mm:ss fff"),
            OpUserName = "",
            RequestMethodName = invocation.Method.Name,
            RequestParamsName = string.Join(", ", invocation.Arguments.Select(a => (a ?? "").ToString()).ToArray()),
            ResponseJsonData = json
        };
        try
        {
            // 如果存在多个拦截器（Interceptor），会触发下一个拦截器的Intercept方法
            // 如果所有拦截器均已执行，则调用原始目标方法（真实对象的实际方法）。
            // 无拦截器时，直接执行目标方法`
            invocation.Proceed();
            // 判断是否是异步方法，需要特殊处理
            if (IsAsyncMethod(invocation.Method))
            {
                // 处理无返回值的异步方法 (Task)
                if (invocation.Method.ReturnType == typeof(Task))
                {
                    invocation.ReturnValue = InternalAsyncHelper.AwaitFinally(
                        (Task)invocation.ReturnValue,
                        async () => await SuccessAction(invocation, apiLogAopInfo, startTime), // 成功后的处理
                        ex => { LogEx(ex, apiLogAopInfo); }); // 异常处理
                }
                // 处理有返回值的异步方法 (Task<T>)
                else
                {
                    invocation.ReturnValue = InternalAsyncHelper.CallAwaitAndGetResult(
                        invocation.Method.ReturnType.GenericTypeArguments[0],
                        invocation.ReturnValue,
                        async (o) => await SuccessAction(invocation, apiLogAopInfo, startTime, o), // 成功后的处理
                        ex => { LogEx(ex, apiLogAopInfo); }); // 异常处理
                }
            }
            else
            {
                // 处理同步方法的返回值
                string jsonResult;
                try
                {
                    // 序列化返回值
                    jsonResult = JsonConvert.SerializeObject(invocation.ReturnValue);
                }
                catch (Exception ex)
                {
                    // 处理无法序列化的返回值
                    jsonResult = "无法序列化，可能是兰姆达表达式等原因造成，按照框架优化代码" + ex.ToString();
                }

                // 计算方法执行时间并记录日志
                DateTime endTime = DateTime.Now;
                string responseTime = (endTime - startTime).Milliseconds.ToString();
                apiLogAopInfo.ResponseTime = endTime.ToString("yyyy-MM-dd hh:mm:ss fff");
                apiLogAopInfo.ResponseIntervalTime = responseTime + "ms";
                apiLogAopInfo.ResponseJsonData = jsonResult;
                Console.WriteLine(JsonConvert.SerializeObject(apiLogAopInfo));
            }
        }
        catch (Exception ex)
        {
            // 记录异常信息并重新抛出异常
            LogEx(ex, apiLogAopInfo);
            throw;
        }
    }

    // 处理异步方法执行成功后的操作
    private async Task SuccessAction(IInvocation invocation, AOPLogInfo apiLogAopInfo, DateTime startTime,
        object o = null)
    {
        // 计算方法执行时间
        DateTime endTime = DateTime.Now;
        string ResponseTime = (endTime - startTime).Milliseconds.ToString();
        apiLogAopInfo.ResponseTime = endTime.ToString("yyyy-MM-dd hh:mm:ss fff");
        apiLogAopInfo.ResponseIntervalTime = ResponseTime + "ms";
        apiLogAopInfo.ResponseJsonData = JsonConvert.SerializeObject(o);

        await Task.Run(() =>
        {
            // 这里可以添加额外的异步处理逻辑，如写入日志到数据库等
            Console.WriteLine("执行成功-->" + JsonConvert.SerializeObject(apiLogAopInfo));
        });
    }

    // 记录异常信息
    private void LogEx(Exception ex, AOPLogInfo dataIntercept)
    {
        if (ex != null)
        {
            // 输出异常信息和拦截的数据
            Console.WriteLine("error!!!:" + ex.Message + JsonConvert.SerializeObject(dataIntercept));
        }
    }

    // 判断方法是否是异步方法
    public static bool IsAsyncMethod(MethodInfo method)
    {
        return
            method.ReturnType == typeof(Task) || // 无返回值的异步方法
            method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>);
        // 有返回值的异步方法
    }
}

// 内部异步帮助类，用于处理异步方法的执行
internal static class InternalAsyncHelper
{
    // 处理无返回值的异步方法
    public static async Task AwaitFinally(Task actualReturnValue, Func<Task> postAction,
        Action<Exception> finalAction)
    {
        Exception exception = null;

        try
        {
            // 等待异步方法执行完成
            await actualReturnValue;
            // 执行后续操作
            await postAction();
        }
        catch (Exception ex)
        {
            exception = ex;
        }
        finally
        {
            // 执行最终的处理操作
            finalAction(exception);
        }
    }

    // 处理有返回值的异步方法
    public static async Task<T> AwaitAndGetResult<T>(Task<T> actualReturnValue,
        Func<object, Task> postAction,
        Action<Exception> finalAction)
    {
        Exception exception = null;
        try
        {
            // 等待异步方法执行完成并获取结果
            var result = await actualReturnValue;
            // 执行后续操作
            await postAction(result);
            return result;
        }
        catch (Exception ex)
        {
            exception = ex;
            throw;
        }
        finally
        {
            // 执行最终的处理操作
            finalAction(exception);
        }
    }

    // 通过反射调用泛型方法
    public static object CallAwaitAndGetResult(Type taskReturnType,
        object actualReturnValue,
        Func<object, Task> action, Action<Exception> finalAction)
    {
        // 使用反射动态调用泛型方法
        return typeof(InternalAsyncHelper)
            .GetMethod("AwaitAndGetResult", BindingFlags.Public | BindingFlags.Static)
            .MakeGenericMethod(taskReturnType)
            .Invoke(null, new object[] { actualReturnValue, action, finalAction });
    }
}